package com.bsj.travel.security.auth;

import cn.hutool.extra.spring.SpringUtil;
import com.bsj.travel.def.global.JsonResultEnum;
import com.bsj.travel.exception.ApiException;
import com.bsj.travel.exception.auth.NotPermissionException;
import com.bsj.travel.exception.auth.NotRoleException;
import com.bsj.travel.security.annotation.Logical;
import com.bsj.travel.security.annotation.RequiresPermissions;
import com.bsj.travel.security.annotation.RequiresRoles;
import com.bsj.travel.security.service.TokenService;
import com.bsj.travel.def.common.VO.TokenUser;
import com.bsj.travel.util.SecurityUtils;
import com.bsj.travel.util.StringUtils;
import org.springframework.util.PatternMatchUtils;

import java.util.Collection;
import java.util.Set;

/**
 * @author yinhao
 * @version 1.0
 * @description Token 权限验证，逻辑实现类
 * @date 2024/1/10
 */
public class AuthLogic {
    /**
     * 所有权限标识
     */
    private static final String ALL_PERMISSION = "*:*:*";

    /**
     * 超级管理员权限标识
     */
    public static final String SUPER_ADMIN = "admin";

    public TokenService tokenService = SpringUtil.getBean(TokenService.class);

    /**
     * 会话注销
     */
    public void logout() {
        String token = SecurityUtils.getToken();
        if (token == null) {
            return;
        }
        logoutByToken(token);
    }

    /**
     * 会话注销，根据指定token
     *
     * @param token
     */
    public void logoutByToken(String token) {
        tokenService.delLoginUser(token);
    }

    /**
     * 校验用户是否已经登录，如未登录，则抛出异常
     */
    public void checkLogin() {
        getLoginUser();
    }

    /**
     * 获取当前用户缓存信息，如果未登录，则抛出异常
     *
     * @return 用户登录缓存信息
     */
    public TokenUser getLoginUser() {
        String token = SecurityUtils.getToken();
        if (token == null) {
            throw new ApiException(JsonResultEnum.NOT_AUTH_ISNULL);
        }
        TokenUser tokenUser = tokenService.getLoginUser(token);
        if (tokenUser == null) {
            throw new ApiException(JsonResultEnum.USER_LOGIN_AUTH_NULL);
        }
        return tokenUser;
    }

    /**
     * 判断用户是否具备某权限
     *
     * @param permission
     * @return
     */
    public boolean hasPerm(String permission) {
        return hasPerm(getPermList(), permission);
    }

    /**
     * 判断是否包含权限
     *
     * @param authorities
     * @param permission
     * @return
     */
    public boolean hasPerm(Collection<String> authorities, String permission) {
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission));
    }

    /**
     * 验证用户是否具备某权限，如果验证未通过，则抛出异常：NotPermissionException
     *
     * @param permission 权限字符串
     * @return 验证用户是否具备某权限
     */
    public void checkPerm(String permission) throws NotPermissionException {
        if (!hasPerm(getPermList(), permission)) {
            throw new NotPermissionException(permission);
        }
    }

    public void checkPerm(RequiresPermissions requiresPermissions) {
        if (requiresPermissions.logical() == Logical.AND) {
            checkPermAnd(requiresPermissions.value());
        } else {
            checkPermOr(requiresPermissions.value());
        }
    }

    /**
     * 判断用户是否含有指定权限，必须全部拥有
     *
     * @param permissions 权限列表
     */
    public void checkPermAnd(String... permissions) {
        Set<String> permissionList = getPermList();
        for (String permission : permissions) {
            if (!hasPerm(permissionList, permission)) {
                throw new NotPermissionException(permission);
            }
        }
    }

    /**
     * 验证用户是否含有指定权限，只需要包含其中一个
     *
     * @param permissions
     */
    public void checkPermOr(String... permissions) {
        Set<String> permissionList = getPermList();
        for (String permission : permissions) {
            if (hasPerm(permissionList, permission)) {
                return;
            }
        }
        if (permissions.length > 0) {
            throw new NotPermissionException(permissions);
        }
    }

    /**
     * 获取当前账号的权限列表
     *
     * @return
     */
    public Set<String> getPermList() {
        TokenUser loginUser = getLoginUser();
        return loginUser.getPermissions();
    }

    /**
     * 根据注解(@RequiresRoles)
     *
     * @param requiresRoles
     */
    public void checkRole(RequiresRoles requiresRoles) {
        if (requiresRoles.logical() == Logical.AND) {
            checkRoleAnd(requiresRoles.value());
        } else {
            checkRoleOr(requiresRoles.value());
        }
    }

    /**
     * 验证用户是否包含指定角色，必须全部拥有
     *
     * @param roles 角色标识数字
     */
    public void checkRoleAnd(String... roles) {
        Set<String> roleList = getRoleList();
        for (String role : roles) {
            if (!hasRole(roleList, role)) {
                throw new NotRoleException(role);
            }
        }
    }

    /**
     * 验证用户是否包含指定角色，只需要包含其中一个
     *
     * @param roles
     */
    public void checkRoleOr(String... roles) {
        Set<String> roleList = getRoleList();
        for (String role : roles) {
            if (hasRole(roleList, role)) {
                return;
            }
        }
        if (roles.length > 0) {
            throw new NotRoleException(roles);
        }
    }

    /**
     * 判断是否包含角色
     *
     * @param roles 角色列表
     * @param role  角色
     * @return 用户是否具备角色权限
     */
    public boolean hasRole(Collection<String> roles, String role) {
        return roles.stream().filter(StringUtils::hasText)
                .anyMatch(x -> SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role));
    }

    /**
     * 获取当前账号的角色列表
     *
     * @return
     */
    public Set<String> getRoleList() {
        TokenUser loginUser = getLoginUser();
        return loginUser.getRoles();
    }
}
